﻿/*----------------------------------------------------------------
//  <copyright file="YfxytSmsInquirer.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-03-04 14:53</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.SMS.Inquirer
{
    #region "逸峰信盈通短信查询者"
    /// <summary>
    /// 逸峰信盈通短信查询者
    /// </summary>
    public class YfxytSmsInquirer : ISmsInquirer
    {
        #region 属性
        #region "获取 服务提供者对象"
        /// <summary>
        /// 获取 服务提供者对象
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 事件总线"
        /// <summary>
        /// 获取 事件总线
        /// </summary>
        protected IEventBus EventBus => ServiceProvider.GetService<IEventBus>();
        #endregion
        #region "获取 日志对象"
        /// <summary>
        /// 获取 日志对象
        /// </summary>
        protected ILogger Logger { get; }
        #endregion
        #region "获取 短信配置选项"
        /// <summary>
        /// 获取 短信配置选项
        /// </summary>
        protected SmsOptions SmsOpt => ServiceProvider.GetService<IConfiguration>()?.GetSmsOptions();
        #endregion

        #region "获取 HttpClient工厂对象"
        /// <summary>
        /// 获取 HttpClient工厂对象
        /// </summary>
        protected IHttpClientFactory HttpClientFactory => ServiceProvider.GetService<IHttpClientFactory>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个逸峰信盈通短信查询者的新实例"
        /// <summary>
        /// 初始化一个逸峰信盈通短信查询者 <see cref="YfxytSmsInquirer"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public YfxytSmsInquirer(IServiceProvider provider)
        {
            ServiceProvider = provider;
            Logger = provider.GetLogger(GetType());
        }
        #endregion

        #endregion

        #region "方法"
        #region "查询短信发送状态"
        /// <summary>
        /// 查询短信发送状态
        /// </summary>
        /// <param name="paramsDto">短信查询参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<StatusResponse>> QuerySentStatusAsync(QueryParamsDto paramsDto)
        {
            var result = await QuerySentStatusByJnyfAsync(SmsOpt.RegionId, SmsOpt.Id, SmsOpt.Secret, SmsOpt.Domain);
            //触发状态查询成功事件
            if (result.Succeeded)
            {
                SmsStatusEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion
        #region "查询短信发送记录"
        /// <summary>
        /// 查询短信发送记录
        /// </summary>
        /// <param name="paramsDto">短信查询参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<QueryResponse>> QuerySentDetailsAsync(QueryParamsDto paramsDto)
        {
            var result = OperationResult.Unsupported<QueryResponse>(I18N.T("逸峰信盈通不支持查询短信发送记录"));
            //触发查询成功事件
            if (result.Succeeded)
            {
                SmsQueryEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion
        #region "查询上行短信消息"
        /// <summary>
        /// 查询上行短信消息
        /// </summary>
        /// <param name="paramsDto">上行短信查询参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<UpResponse>> QueryUpDetailsAsync(UpParamsDto paramsDto)
        {
            var result = await QueryUpByJnyfAsync(SmsOpt.RegionId, SmsOpt.Id, SmsOpt.Secret, SmsOpt.Domain);
            //触发查询成功事件
            if (result.Succeeded)
            {
                SmsUpEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion

        #endregion

        #region "受保护方法"
        #region "以逸峰信盈通作为服务商查询短信发送状态"
        /// <summary>
        /// 以逸峰信盈通作为服务商查询短信发送状态
        /// </summary>
        /// <param name="regionId">区域ID</param>
        /// <param name="accessKeyId">密钥Id</param>
        /// <param name="accessKeySecret">密钥Secret</param>
        /// <param name="domain">产品域名</param>
        /// <returns></returns>
        protected virtual async Task<OperationResult<StatusResponse>> QuerySentStatusByJnyfAsync(string regionId, string accessKeyId, string accessKeySecret, string domain)
        {
            regionId = regionId.IsMissing() ? JnyfConstants.RegionId : regionId;
            domain = domain.IsMissing() ? JnyfConstants.Domain : domain;

            Check.NotNullOrEmpty(accessKeyId, nameof(accessKeyId));
            Check.NotNullOrEmpty(accessKeySecret, nameof(accessKeySecret));

            var request = new HttpRequestMessage(HttpMethod.Post,
            $"http://{domain}/{regionId}/{JnyfConstants.StatusReportAction}");
            var md5AccessKeySecret = accessKeySecret.ToMD5().ToLower();

            var nameValueCollection = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("acctno", accessKeyId),
                new KeyValuePair<string, string>("password", md5AccessKeySecret),
            };
            request.Content = new FormUrlEncodedContent(nameValueCollection);

            var client = HttpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            var responseContentStr = await response.Content.ReadAsStringAsync();

            var smsStatusResponse = new StatusResponse
            {
                RequestId = Guid.NewGuid().ToString()
            };
            if (!response.IsSuccessStatusCode)
            {
                smsStatusResponse.Code = response.StatusCode.ToString();
                smsStatusResponse.Message = responseContentStr;

                var result1 = OperationResult.Error(smsStatusResponse);
                return await Task.Factory.StartNew(() => result1);
            }
            //处理XML返回结果
            try
            {
                XmlDocument xmldoc = new();
                xmldoc.LoadXml(responseContentStr);
                XmlNode xmlNodeReturnSms = xmldoc.SelectSingleNode("returnsms");
                if (xmlNodeReturnSms == null)
                {
                    smsStatusResponse.Code = response.StatusCode.ToString();
                    smsStatusResponse.Message = responseContentStr;

                    var result2 = OperationResult.Error(smsStatusResponse);
                    return await Task.Factory.StartNew(() => result2);
                }
                string errorstatus = xmlNodeReturnSms.SelectSingleNode("errorstatus")?.InnerText;
                if (errorstatus != null)
                {
                    smsStatusResponse.Code = response.StatusCode.ToString();
                    smsStatusResponse.Message = errorstatus;

                    var result2 = OperationResult.Error(smsStatusResponse);
                    return await Task.Factory.StartNew(() => result2);
                }

                smsStatusResponse.Code = "OK";
                smsStatusResponse.TotalCount = "0";
                smsStatusResponse.Message = "短信状态查询成功";

                XmlNodeList xmlNodeListStatus = xmlNodeReturnSms.SelectNodes("statusbox");
                if (xmlNodeListStatus.Count <= 0)
                {
                    var result3 = OperationResult.Success(smsStatusResponse);
                    return await Task.Factory.StartNew(() => result3);
                }
                foreach (XmlNode xmlNodeStatus in xmlNodeListStatus)
                {
                    string mobile = xmlNodeStatus.SelectSingleNode("mobile")?.InnerText;
                    string taskid = xmlNodeStatus.SelectSingleNode("taskid")?.InnerText;
                    string time = xmlNodeStatus.SelectSingleNode("time")?.InnerText;
                    string status = xmlNodeStatus.SelectSingleNode("status")?.InnerText;
                    string errorcode = xmlNodeStatus.SelectSingleNode("errorcode")?.InnerText;

                    smsStatusResponse.StatusDtos.Add(new StatusDto
                    {
                        PhoneNum = mobile,
                        BizId = taskid,
                        ReceiveDate = time,
                        ReceiveStatus = status.Contains("成功") ? SmsReceiveStatus.Succeeded : status.Contains("失败") ? SmsReceiveStatus.Failed : SmsReceiveStatus.Waiting,
                        SendDate = time,
                        SendStatus = status.Contains("成功") ? SmsSendStatus.Succeeded : status.Contains("失败") ? SmsSendStatus.Failed : SmsSendStatus.Waiting,
                        ErrCode = errorcode,
                        Message = status,
                    });
                }

                smsStatusResponse.TotalCount = smsStatusResponse.StatusDtos.Count.ToString();

                var result = OperationResult.Success(smsStatusResponse);
                return await Task.Factory.StartNew(() => result);
            }
            catch
            {
                //smsSentResponse.Code = response.StatusCode.ToString();
                //smsSentResponse.Message = responseContentStr;
                smsStatusResponse.Code = "ValidError";
                smsStatusResponse.Message = I18N.T("调用接口返回错误，有可能参数设置不正确！");

                var result = OperationResult.Error(smsStatusResponse);
                return await Task.Factory.StartNew(() => result);
            }
        }
        #endregion
        #region "以逸峰信盈通作为服务商查询上行短信消息记录"
        /// <summary>
        /// 以逸峰信盈通作为服务商查询上行短信消息记录
        /// </summary>
        /// <param name="regionId">区域ID</param>
        /// <param name="accessKeyId">密钥Id</param>
        /// <param name="accessKeySecret">密钥Secret</param>
        /// <param name="domain">产品域名</param>
        /// <returns></returns>
        protected virtual async Task<OperationResult<UpResponse>> QueryUpByJnyfAsync(string regionId, string accessKeyId, string accessKeySecret, string domain)
        {
            regionId = regionId.IsMissing() ? JnyfConstants.RegionId : regionId;
            domain = domain.IsMissing() ? JnyfConstants.Domain : domain;

            Check.NotNullOrEmpty(accessKeyId, nameof(accessKeyId));
            Check.NotNullOrEmpty(accessKeySecret, nameof(accessKeySecret));

            var request = new HttpRequestMessage(HttpMethod.Post,
            $"http://{domain}/{regionId}/{JnyfConstants.ReceiveAction}");
            var md5AccessKeySecret = accessKeySecret.ToMD5().ToLower();

            var nameValueCollection = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("acctno", accessKeyId),
                new KeyValuePair<string, string>("password", md5AccessKeySecret),
            };
            request.Content = new FormUrlEncodedContent(nameValueCollection);

            var client = HttpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            var responseContentStr = await response.Content.ReadAsStringAsync();

            var smsUpResponse = new UpResponse
            {
                RequestId = Guid.NewGuid().ToString()
            };
            if (!response.IsSuccessStatusCode)
            {
                smsUpResponse.Code = response.StatusCode.ToString();
                smsUpResponse.Message = responseContentStr;

                var result1 = OperationResult.Error(smsUpResponse);
                return await Task.Factory.StartNew(() => result1);
            }
            //处理XML返回结果
            try
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(responseContentStr);
                XmlNode xmlNodeReturnSms = xmldoc.SelectSingleNode("returnsms");
                if (xmlNodeReturnSms == null)
                {
                    smsUpResponse.Code = response.StatusCode.ToString();
                    smsUpResponse.Message = responseContentStr;

                    var result2 = OperationResult.Error(smsUpResponse);
                    return await Task.Factory.StartNew(() => result2);
                }
                string errorstatus = xmlNodeReturnSms.SelectSingleNode("errorstatus")?.InnerText;
                if (errorstatus != null)
                {
                    smsUpResponse.Code = response.StatusCode.ToString();
                    smsUpResponse.Message = errorstatus;

                    var result2 = OperationResult.Error(smsUpResponse);
                    return await Task.Factory.StartNew(() => result2);
                }

                smsUpResponse.Code = "OK";
                smsUpResponse.Message = "上行短信查询成功";

                XmlNodeList xmlNodeListStatus = xmlNodeReturnSms.SelectNodes("callbox");
                if (xmlNodeListStatus.Count <= 0)
                {
                    var result3 = OperationResult.Success(smsUpResponse);
                    return await Task.Factory.StartNew(() => result3);
                }
                foreach (XmlNode xmlNodeStatus in xmlNodeListStatus)
                {
                    string mobile = xmlNodeStatus.SelectSingleNode("mobile")?.InnerText;
                    string spcode = xmlNodeStatus.SelectSingleNode("spcode")?.InnerText;
                    string taskid = xmlNodeStatus.SelectSingleNode("taskid")?.InnerText;
                    string content = xmlNodeStatus.SelectSingleNode("content")?.InnerText;
                    string receivetime = xmlNodeStatus.SelectSingleNode("receivetime")?.InnerText;

                    smsUpResponse.UpDetailDtos.Add(new UpDetailDto
                    {
                        PhoneNumber = mobile,
                        OutId = spcode,
                        Content = content,
                        SendDate = receivetime,
                        BizId = taskid,
                    });
                }

                var result = OperationResult.Success(smsUpResponse);
                return await Task.Factory.StartNew(() => result);
            }
            catch
            {
                //smsSentResponse.Code = response.StatusCode.ToString();
                //smsSentResponse.Message = responseContentStr;
                smsUpResponse.Code = "ValidError";
                smsUpResponse.Message = I18N.T("调用接口返回错误，有可能参数设置不正确！");

                var result = OperationResult.Error(smsUpResponse);
                return await Task.Factory.StartNew(() => result);
            }
        }
        #endregion

        #endregion

    }
    #endregion

}
